/******************************************************************************
 *  Copyright 2013 Bernhard Grünewaldt                                        *
 *                                                                            *
 *  Licensed under the Apache License, Version 2.0 (the "License");           *
 *  you may not use this file except in compliance with the License.          *
 *  You may obtain a copy of the License at                                   *
 *                                                                            *
 *      http://www.apache.org/licenses/LICENSE-2.0                            *
 *                                                                            *
 *  Unless required by applicable law or agreed to in writing, software       *
 *  distributed under the License is distributed on an "AS IS" BASIS,         *
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 *  See the License for the specific language governing permissions and       *
 *  limitations under the License.                                            *
 ******************************************************************************/
package com.google.code.greenwood.confluencemavenreleaseinfomacro.pojo.diff;

import java.util.Date;

import org.jfree.util.Log;

import com.google.code.greenwood.confluencemavenreleaseinfomacro.pojo.ArtifactInformation;
import com.google.code.greenwood.confluencemavenreleaseinfomacro.pojo.ModuleReleaseVersion;
import com.google.code.greenwood.confluencemavenreleaseinfomacro.pojo.Properties;
import com.google.code.greenwood.confluencemavenreleaseinfomacro.pojo.ReleaseInformation;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;

public class ReleaseInformationDiff {

	protected Date lastCacheUpdate = null;

	private ReleaseInformation releaseInformationOne;
	private ReleaseInformation releaseInformationTwo;
	
	// contains an union of both
	private ReleaseInformation mergedInformation;
	
	public ReleaseInformation getReleaseInformationOne() {
		return releaseInformationOne;
	}

	public void setReleaseInformationOne(ReleaseInformation releaseInformationOne) {
		this.releaseInformationOne = releaseInformationOne;
	}

	public ReleaseInformation getReleaseInformationTwo() {
		return releaseInformationTwo;
	}

	public void setReleaseInformationTwo(ReleaseInformation releaseInformationTwo) {
		this.releaseInformationTwo = releaseInformationTwo;
	}

	public Date getLastCacheUpdate() {
		return lastCacheUpdate;
	}

	public void setLastCacheUpdate(Date lastCacheUpdate) {
		this.lastCacheUpdate = lastCacheUpdate;
	}

	/**
	 * get a Union of both releases
	 */
	public void generateMergedInformation() {
		this.mergedInformation = new ReleaseInformation();
		ReleaseInformation releaseInformationOneWork = new ReleaseInformation();
		ReleaseInformation releaseInformationTwoWork = new ReleaseInformation();
		try {
			// Deep copy, otherwise merging won't work as expected
			releaseInformationOneWork = (ReleaseInformation) releaseInformationOne.clone();
			releaseInformationTwoWork = (ReleaseInformation) releaseInformationTwo.clone();
		} catch (CloneNotSupportedException e) {
			Log.error(e);
		}
		
		
		ImmutableSet<ModuleReleaseVersion> releaseInformationOneModules = ImmutableSet.copyOf(releaseInformationOneWork.getModules());
		ImmutableSet<ModuleReleaseVersion> releaseInformationTwoModules = ImmutableSet.copyOf(releaseInformationTwoWork.getModules());
		ImmutableSet<ModuleReleaseVersion> mergedModules = ModuleReleaseVersion.getUnionOfModuleReleaseVersionLists(releaseInformationOneModules, releaseInformationTwoModules);
		for (ModuleReleaseVersion mergedmodule : mergedModules) {
			
			
			ModuleReleaseVersion moduleOne = releaseInformationOneWork.getModulByModulename(mergedmodule.getName());
			ModuleReleaseVersion moduleTwo = releaseInformationTwoWork.getModulByModulename(mergedmodule.getName());
			ImmutableSet<ArtifactInformation> dependenciesOne = null;
				if (moduleOne != null) dependenciesOne = ImmutableSet.copyOf(moduleOne.getDependencies());
			ImmutableSet<ArtifactInformation> dependenciesTwo = null; 
				if (moduleTwo != null) dependenciesTwo = ImmutableSet.copyOf(moduleTwo.getDependencies());

			ImmutableSet<ArtifactInformation> mergedDependencies = null;
			ImmutableSet<Properties> mergedProperties = null;
			if (dependenciesOne != null && dependenciesTwo != null) {
				mergedDependencies = ArtifactInformation.getUnionOfModuleReleaseVersionDependenciesLists(dependenciesOne, dependenciesTwo);
				mergedProperties = Properties.getUnionOfModuleReleaseVersionPropertiesLists(ImmutableSet.copyOf(moduleOne.getProperties()), ImmutableSet.copyOf(moduleTwo.getProperties()));
			} else if (dependenciesOne != null && dependenciesTwo == null) {
				mergedDependencies = ImmutableSet.copyOf(dependenciesOne);
				mergedProperties = ImmutableSet.copyOf(moduleOne.getProperties());
			} else if (dependenciesOne == null && dependenciesTwo != null) {
				mergedDependencies = ImmutableSet.copyOf(dependenciesTwo);
				mergedProperties = ImmutableSet.copyOf(moduleTwo.getProperties());
			}
			mergedmodule.setDependencies(mergedDependencies);
			mergedmodule.setProperties(mergedProperties);
		}
		this.mergedInformation.addModules(mergedModules);
	}

	public ReleaseInformation getMergedInformation() {
		return mergedInformation;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime
				* result
				+ ((mergedInformation == null) ? 0 : mergedInformation
						.hashCode());
		result = prime
				* result
				+ ((releaseInformationOne == null) ? 0 : releaseInformationOne
						.hashCode());
		result = prime
				* result
				+ ((releaseInformationTwo == null) ? 0 : releaseInformationTwo
						.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReleaseInformationDiff other = (ReleaseInformationDiff) obj;
		if (mergedInformation == null) {
			if (other.mergedInformation != null)
				return false;
		} else if (!mergedInformation.equals(other.mergedInformation))
			return false;
		if (releaseInformationOne == null) {
			if (other.releaseInformationOne != null)
				return false;
		} else if (!releaseInformationOne.equals(other.releaseInformationOne))
			return false;
		if (releaseInformationTwo == null) {
			if (other.releaseInformationTwo != null)
				return false;
		} else if (!releaseInformationTwo.equals(other.releaseInformationTwo))
			return false;
		return true;
	}

	
	
	
}
